package tc.alert.tckejisoc.rule;

import org.apache.commons.beanutils.BeanUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import tc.alert.tckejisoc.domain.EventBase;
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Component
public class LogRuleManager {
    private static final Logger log = LoggerFactory.getLogger(LogRuleManager.class);
    // 类成员变量声明
    private Map<String, LogRule> rules = new ConcurrentHashMap<>();
    private Path rulesDir;

    // 构造函数
    public void start(String rulesPath) {
        this.rulesDir = Paths.get(rulesPath).toAbsolutePath().normalize();
        validateRulesDir();
        loadAllRules();
        startWatcher();
    }

    // 验证规则目录
    private void validateRulesDir() {
        if (!Files.exists(rulesDir)) {
            throw new IllegalArgumentException("规则目录不存在: " + rulesDir);
        }
        if (!Files.isDirectory(rulesDir)) {
            throw new IllegalArgumentException("路径不是目录: " + rulesDir);
        }
        if (!Files.isReadable(rulesDir)) {
            throw new SecurityException("无目录读取权限: " + rulesDir);
        }
    }

    // 加载所有规则
    private void loadAllRules() {
        try (DirectoryStream<Path> stream = Files.newDirectoryStream(rulesDir, "*.xml")) {
            for (Path file : stream) {
                loadRule(file);
            }
        } catch (IOException e) {
            throw new RuntimeException("规则加载失败", e);
        }
    }

    // 加载单个规则文件
    private void loadRule(Path file) {
        try (InputStream is = Files.newInputStream(file)) {
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
            Document doc = dbf.newDocumentBuilder().parse(is);

            NodeList ruleNodes = doc.getElementsByTagName("log-rule");
            for (int i = 0; i < ruleNodes.getLength(); i++) {
                Element ruleElem = (Element) ruleNodes.item(i);
                LogRule rule = parseLogRule(ruleElem);
                rules.put(rule.getName(), rule);
                log.info("加载规则: ---------------------------------" + rules.toString());
            }
        } catch (Exception e) {
            log.debug("加载规则文件失败: " + file);
            e.printStackTrace();
        }
    }

    // 解析日志规则
    private LogRule parseLogRule(Element ruleElem) throws ClassNotFoundException, NoSuchMethodException {
        LogRule rule = new LogRule();
        rule.setName(ruleElem.getAttribute("name"));

        Element matchElem = (Element) ruleElem.getElementsByTagName("match").item(0);
        rule.setMatcher(new RuleMatcher(
                matchElem.getAttribute("type"),
                matchElem.getTextContent().trim()
        ));

        List<FieldMapping> mappings = new ArrayList<>();
        NodeList fieldNodes = ruleElem.getElementsByTagName("field");
        for (int i = 0; i < fieldNodes.getLength(); i++) {
            Element fieldElem = (Element) fieldNodes.item(i);
            mappings.add(parseFieldMapping(matchElem.getAttribute("type"), fieldElem));
        }
        rule.setFieldMappings(mappings);

        return rule;
    }

    // 解析字段映射
    private FieldMapping parseFieldMapping(String type, Element fieldElem) throws ClassNotFoundException, NoSuchMethodException {
//        String type = fieldElem.getAttribute("type");
        String target = fieldElem.getAttribute("target");

        switch (type) {
            case "regex":
                return new RegexMapping(
                        target,
                        fieldElem.getAttribute("source-type"),
                        Integer.parseInt(fieldElem.getAttribute("source"))
                );
            case "jsonpath":
                return new JsonPathMapping(target, fieldElem.getAttribute("path"));
            case "handler":
                return new HandlerMapping(
                        target,
                        fieldElem.getAttribute("class"),
                        fieldElem.getAttribute("method")
                );
            default:
                throw new IllegalArgumentException("不支持的映射类型: " + type);
        }
    }

    // 文件监控线程
    private void startWatcher() {
        new Thread(() -> {
            try (WatchService watcher = FileSystems.getDefault().newWatchService()) {
                rulesDir.register(watcher,
                        StandardWatchEventKinds.ENTRY_MODIFY,
                        StandardWatchEventKinds.ENTRY_CREATE,
                        StandardWatchEventKinds.ENTRY_DELETE
                );

                log.debug("开始监控规则目录: " + rulesDir);

                while (!Thread.currentThread().isInterrupted()) {
                    WatchKey key = watcher.take();
                    for (WatchEvent<?> event : key.pollEvents()) {
                        handleWatchEvent(event);
                    }
                    if (!key.reset()) {
                        log.debug("监控密钥失效");
                        break;
                    }
                }
            } catch (ClosedWatchServiceException e) {
                log.debug("监控服务正常关闭");
            } catch (InterruptedException e) {
                log.debug("文件监控被中断");
                Thread.currentThread().interrupt();
            } catch (IOException e) {
                log.debug("文件监控初始化失败: " + e.getMessage());
                e.printStackTrace();
            } catch (Exception e) {
                log.debug("未知监控错误: " + e.getMessage());
                e.printStackTrace();
            }
        }, "RuleFileWatcher").start();
    }

    // 处理文件事件
    private void handleWatchEvent(WatchEvent<?> event) {
        Path changedFile = rulesDir.resolve((Path) event.context());
        String fileName = changedFile.getFileName().toString();

        if (!fileName.endsWith(".xml")) return;

        switch (event.kind().name()) {
            case "ENTRY_MODIFY":
                log.debug("检测到文件修改: " + fileName);
                reloadRule(changedFile);
                break;
            case "ENTRY_CREATE":
                log.debug("新增规则文件: " + fileName);
                loadRule(changedFile);
                break;
            case "ENTRY_DELETE":
                log.debug("删除规则文件: " + fileName);
                rules.remove(fileName.replace(".xml", ""));
                break;
        }
    }

    // 重新加载规则
    private void reloadRule(Path file) {
        try {
            // 先删除旧规则
            String ruleName = file.getFileName().toString().replace(".xml", "");
            rules.remove(ruleName);

            // 加载新规则
            loadRule(file);

            log.debug("规则重载成功: " + file);
        } catch (Exception e) {
            log.debug("规则重载失败: " + file);
            e.printStackTrace();
        }
    }

    // 日志解析入口
    public EventBase parseLog(String rawLog, String name) {

        LogRule logRule = rules.get(name);
        if (null == logRule) {
            log.info("无法匹配解析规则请关注 --------------------------------------" + name);
            return null;
        }
        EventBase result = new EventBase();
        for (FieldMapping mapping : logRule.getFieldMappings()) {
            String value = mapping.extractValue(rawLog);
            try {
                BeanUtils.setProperty(result, mapping.getTarget(), value);
            } catch (Exception e) {
                log.debug("字段映射失败: " + mapping.getTarget());
            }
        }
        return result;
    }
//        for (LogRule rule : rules.values()) {
//            //根据xml名称匹配解析规则
//            rule.getName()
//
//
//
//            //解析
////           if(rule.getMatcher().equals("jsonpath")){
////
////           }else if (rule.getMatcher().matches(rawLog)) {
////                UnifiedLog result = new UnifiedLog();
////                for (FieldMapping mapping : rule.getFieldMappings()) {
////                    String value = mapping.extractValue(rawLog);
////                    try {
////                        BeanUtils.setProperty(result, mapping.getTarget(), value);
////                    } catch (Exception e) {
////                        log.debug("字段映射失败: " + mapping.getTarget());
////                    }
////                }
////                return result;
////            }
////        }
//        throw new RuntimeException("未匹配到任何规则");
//    }
}